package com.zhengxing.jienci.redis.util;

import com.zhengxing.jienci.redis.annotation.DelCache;
import com.zhengxing.jienci.redis.annotation.SaveCache;
import com.zhengxing.jienci.redis.enums.CacheStrategy;
import org.aspectj.lang.JoinPoint;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Map;

/**
 * @author 浪遏飞舟
 * @create 2020-06-22 14:39
 * 对key值操作的工具类
 */
public class KeyUtils {


    /**
     * 获得缓存key
     * @param cacheAnno
     * @return
     */
    public static String getCacheKey(DelCache cacheAnno, JoinPoint point)throws Exception{
        //获得缓存策略
        CacheStrategy strategy = cacheAnno.strategy();
        String key = "";
        //固定值
        String[] fixedValues = cacheAnno.fixedValues();
        //属性名
        String[] attrs = cacheAnno.attrs();
        //获得属性key
        if (strategy == CacheStrategy.FIXED_AND_ATTR){
            key = getKeyByArray(fixedValues,attrs,point);
        }else if(strategy == CacheStrategy.FIXED_VALUE){
            key = getKeyByArray(fixedValues,null,point);
        }else if(strategy == CacheStrategy.ATTR){
            key = getKeyByArray(null,attrs,point);
        }
        return key;
    }

    /**
     * 获得缓存key
     * @param cacheAnno
     * @return
     */
    public static String getCacheKey(SaveCache cacheAnno, JoinPoint point)throws Exception{
        //获得缓存策略
        CacheStrategy strategy = cacheAnno.strategy();
        String key = "";
        //固定值
        String[] fixedValues = cacheAnno.fixedValues();
        //属性名
        String[] attrs = cacheAnno.attrs();
        //获得属性key
        if (strategy == CacheStrategy.FIXED_AND_ATTR){
            key = getKeyByArray(fixedValues,attrs,point);
        }else if(strategy == CacheStrategy.FIXED_VALUE){
            key = getKeyByArray(fixedValues,null,point);
        }else if(strategy == CacheStrategy.ATTR){
            key = getKeyByArray(null,attrs,point);
        }
        return key;
    }




    /**
     * 拼接固定值和指定的属性值
     * @param fixeds 固定值数组
     * @param attrs 属性名数组
     * @param point 连接点
     * @return 拼接后的字符串
     */
    public static String getKeyByArray(String[] fixeds,String[] attrs,JoinPoint point)throws Exception{
        //保存拼接字符串
        StringBuilder str = new StringBuilder();
        //拼接固定值
        if (fixeds != null && fixeds.length > 0){
            for (int i = 0 ; i < fixeds.length ; i++){
                if (i == fixeds.length - 1){
                    str.append(fixeds[i]);
                }else{
                    str.append(fixeds[i] + ":");
                }
            }
        }
        //拼接属性值
        if (attrs != null && attrs.length > 0){
            Object[] args = point.getArgs();
            //根据属性名获得属性值
            String[] attrValues = getValuesByAttrs(attrs,args);
            for (int i = 0 ; i < attrValues.length ; i++){
                //前面有固定值拼接时需要加上:
                if (str.length() > 0 && i == 0){
                    if (i == attrValues.length - 1){
                        str.append(":" + attrValues[i]);
                    }else{
                        str.append(":" + attrValues[i] + ":");
                    }
                }else{
                    if (i == attrValues.length - 1){
                        str.append(attrValues[i]);
                    }else{
                        str.append(attrValues[i] + ":");
                    }
                }
            }
        }
        return str.toString();
    }


    /**
     * 根据指定的属性名或几个属性数量获得属性值数组
     * @param attrs 属性名数组
     * @param args 方法实参
     * @return  属性值数组
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static String[] getValuesByAttrs(String[] attrs,Object[] args) throws NoSuchFieldException, IllegalAccessException {
        StringBuffer result = new StringBuffer();
        //获得属性数组里面第一个参数
        String attr = attrs[0];
        //判断里面是不是都是数字
        boolean isNum = isNumer(attr);
        //如果是数字就看指定了几个参数
        if (isNum){
            //将这些参数存到数组
            String[] values = new String[Integer.parseInt(attr)];
            for (int i = 0 ; i < Integer.parseInt(attr) ; i++ ){
                values[i] = String.valueOf(args[i]);
            }
            return values;
        }else{
            //如果第一个参数不是数字就从参数列表取出来第一参数并从里面取属性值
            String[] values = new String[attrs.length];
            Object arg = args[0];
            //从Map里面取值
            if(arg instanceof Map){
                for (int i = 0 ; i < attrs.length ; i++){
                    values[i] = String.valueOf(((Map)arg).get(attrs[i]));
                }
            }else{
                //从实体类里面取值
                Class<?> argClass = arg.getClass();
                for (int i = 0 ; i < attrs.length ; i++){
                    Field field = argClass.getDeclaredField(attrs[i]);
                    field.setAccessible(true);
                    values[i] = String.valueOf(field.get(arg));
                }
            }
            return values;
        }
    }

    /**
     * 判断一个字符串是不是数字
     * @param str
     * @return
     */
    public static boolean isNumer(String str) {
        for (int i = 0; i < str.length(); i++) {
            System.out.println(str.charAt(i));
            if (!Character.isDigit(str.charAt(i))) {
                return false;
            }
        }
        return true;
    }


    /**
     * 获得返回结果的类型
     * @param result
     * @return
     */
    public static String getResultType(Object result){
        //返回值是list集合返回list
        if (result instanceof Collection){
            return "List";
        }
        //返回值是map要看看是不是有状态码的map
        if (result instanceof Map){
            if (((Map)result).get("data") != null && ((Map) result).get("result") != null){
                return getResultType(((Map) result).get("data"));
            }
            return "Map";
        }
        if (result instanceof Number || result instanceof String){
            return "String";
        }
        return "Map";
    }

    public static Object getResult(Object result){
        //返回值是map要看看是不是有状态码的map
        if (result instanceof Map){
            if (((Map)result).get("data") != null && ((Map) result).get("result") != null){
                return getResult(((Map) result).get("data"));
            }
        }
        return result;
    }



}
